//
// Created by benxb on 2021/12/24.
//

#include <gtest/gtest.h>
#include <index/linear_index.h>

/**
 * Append 3 page indexes and check split segments
 */
TEST(LinearIndexTest, AppendIndex) {
    benxdb::Column col("x", benxdb::FLOAT);
    benxdb::LinearIndex linear_index("test", col);
    benxdb::LinearIndexPage page(benxdb::STYPE_FLOAT);
    int page_count = page.GetFreeSlotSize();
    int total_count = page_count*3+1;
    int index_size = 4;
    char* index_data = new char[total_count*index_size];
    for (int i = 0; i < total_count; i++) {
        float key = i;
        memcpy(index_data + i*index_size, &key, index_size);
    }
    linear_index.GenerateIndex(index_data, total_count*index_size, 0);
    auto indexes = linear_index.GetIndexes();
    ASSERT_EQ(indexes.size(), 2);
    ASSERT_EQ(indexes[0].seg_id, 0);
    ASSERT_EQ(indexes[1].key.GetAs<float>(), (total_count-1)*1.0/2);
    ASSERT_EQ(indexes[1].seg_id, 1);
}

/**
 * Append 10 page indexes and check split segments
 */
TEST(LinearIndexTest, AppendManyIndex) {
    benxdb::Column col("x", benxdb::FLOAT);
    benxdb::LinearIndex linear_index("test", col);
    benxdb::LinearIndexPage page(benxdb::STYPE_FLOAT);
    int page_count = page.GetFreeSlotSize();
    int index_size = 4;
    int total_count = 10*page_count;
    char* index_data = new char[page_count*index_size];
    for (int k = 0; k < 10; k++) {
        for (int i = 0; i < page_count; i++) {
            float key = k*page_count+i;
            memcpy(index_data + i * index_size, &key, index_size);
        }
        linear_index.GenerateIndex(index_data, page_count*index_size, k*page_count);
    }
    std::vector<benxdb::LinearIndexLeafPair> pairs;
    linear_index.GetAllLeafIndexPairs(pairs);
    ASSERT_EQ(pairs.size(), total_count);
    int cur = 0;
    for (auto pair : pairs) {
        ASSERT_EQ(pair.key.GetAs<float>(), cur);
        ASSERT_EQ(pair.record_id, cur);
        cur++;
    }
}


/**
 * Append 10 page indexes and query
 */
TEST(LinearIndexTest, QueryIndex) {
    benxdb::Column col("x", benxdb::FLOAT);
    benxdb::LinearIndex linear_index("test", col);
    benxdb::LinearIndexPage page(benxdb::STYPE_FLOAT);
    int page_count = page.GetFreeSlotSize();
    int index_size = 4;
    char* index_data = new char[page_count*index_size];
    for (int k = 0; k < 10; k++) {
        for (int i = 0; i < page_count; i++) {
            float key = k*page_count+i;
            memcpy(index_data + i * index_size, &key, index_size);
        }
        linear_index.GenerateIndex(index_data, page_count*index_size, k*page_count);
    }
    benxdb::IndexQuery query(benxdb::LESS_EQUAL, benxdb::LinearIndexKey(benxdb::STYPE_FLOAT, 2100.f));
    std::vector<benxdb::LinearIndexLeafPair> res;
    std::vector<benxdb::IndexQuery> queries = {query};
    linear_index.QueryIndexes(queries, res);
    ASSERT_EQ(res.size(), 2101);
    for (int i = 0; i < res.size(); i++) {
        ASSERT_EQ(res[i].key.GetAs<float>(), i);
        ASSERT_EQ(res[i].record_id, i);
    }

    benxdb::IndexQuery query1(benxdb::GREATER_EQUAL, benxdb::LinearIndexKey(benxdb::STYPE_FLOAT, 2100.f));
    benxdb::IndexQuery query2(benxdb::LESS_EQUAL, benxdb::LinearIndexKey(benxdb::STYPE_FLOAT, 7102.f));
    res.clear();
    queries = {query1, query2};
    linear_index.QueryIndexes(queries, res);
    ASSERT_EQ(res.size(), 5003);
    for (int i = 0; i < res.size(); i++) {
        ASSERT_EQ(res[i].key.GetAs<float>(), i+2100);
        ASSERT_EQ(res[i].record_id, i+2100);
    }
}

int main(int argc, char **argv) {
    testing::InitGoogleTest(&argc,argv);
    return RUN_ALL_TESTS();
}